package com.android.nextBus.Activities;


import java.util.ArrayList;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.app.TimePickerDialog;
import android.app.ListActivity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.TimePicker;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import com.android.nextBus.Activities.ViewRouteMapActivity.PointOverlay;
import com.android.nextBus.DB.SQLiteOperationsWrapper;
import com.android.nextBus.JSON.BaseServicesURL;
import com.android.nextBus.JSON.JSONBusStopHTTPGet;
import com.android.nextBus.JSON.StopParser;
import com.android.nextBus.JSON.TripsTimesItem;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;
import com.google.android.maps.Projection;

/**
 * @author eric
 *
 */
public class ViewTimesActivity extends MapActivity {


	private Context ct;
	// keys for the intent passing to the RouteMapActivity
	public static final String SHAPE_ID_KEY = "shapeID_key";
	public static final String TRIP_NAME_KEY = "trip_name_key";
	public static final String STOP_LAT_KEY = "stop_lat_key";
	public static final String STOP_LON_KEY = "stop_lon_key";
	
	// stop and trip data
	private int listSize;
	private int stopID;
	private String stopName;
	private List<TripsTimesItem> timesList;
	
	// GUI components
	private Button saveFavoriteButton;
	//private Spinner timeSpinner;
	private TextView dateText;
	private TextView timesHeader;
	private TextView timeText;
	
	// arrays for trip information
	int[] shapeIDs;
	String[] routeNames;
	int[] times;
	String[] tripNames;
	String[] tripHeadSigns;

	// calendar and date variables
	int currentDay;
	String currentTime;
	String currentDate;
	String selectedDate;
	String selectedTime;
	String sTime;
	String dateLabel;
	String timeLabel;
	Date d;
	Calendar date = Calendar.getInstance();
	int pHour;
	int pMin;
	
	String hour;
	String min;
	
	// database variable
	
	MapView map;
	MapController mapController;
	PointOverlay myPointOverlay;
	
	private GeoPoint center;
	
	private Projection projection;
	private String[] longAndLat;
	private List<Overlay> mapOverlays;
	private ListView lv;
	
	//"final" means that you cannot assign another reference to the ProgressBar
	private  ProgressBar progess ; 
	private TextView txtLoading ;
	
	ArrayAdapter<String> tsAdapter;
	
	SQLiteOperationsWrapper db;
	
	
	@Override
	public void onCreate(Bundle savedInstanceState){
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.times_layout);
		ct = this;
		progess = (ProgressBar) findViewById(R.id.ProgressBar); 
		txtLoading = (TextView) findViewById(R.id.loading);
		
		progess.setVisibility(View.VISIBLE);  
		txtLoading.setVisibility(View.VISIBLE);  
		
		
		// MapView object that holds the map
		map = (MapView) findViewById(R.id.map);
		// Configure the Map
		map.setBuiltInZoomControls(true);
		map.setSatellite(false);
		
        List<Overlay> mapOverlays = map.getOverlays(); 
        
        Drawable drawable = this.getResources().getDrawable(R.drawable.next_bus_pin_small);
        myPointOverlay = new PointOverlay(drawable, this); 
        
        // sets rID to the value passed through the intent.
     	// NOT SURE IF THERE IS A BETTER WAY OF DOING THIS
     	stopID = getIntent().getIntExtra(ViewStopsActivity.STOP_ID_KEY, -1);
     	stopName = getIntent().getStringExtra(ViewStopsActivity.STOP_NAME_KEY);
     		
     	center  = new GeoPoint((int) (getIntent().getExtras().getInt(ViewStopsActivity.STOP_LAT_KEY)),
     						   (int) (getIntent().getExtras().getInt(ViewStopsActivity.STOP_LONG_KEY)));
     		
        OverlayItem overlayitem = new OverlayItem(center, "Hello", "!"); 
     		
        
        myPointOverlay.addOverlay(overlayitem);
        mapOverlays.add(myPointOverlay);
             
		mapController = map.getController();
		mapController.animateTo(center);

		dateText = (TextView) findViewById(R.id.time_spinner_label);
		timeText = (TextView) findViewById(R.id.time_label);

		mapController.setZoom(19);

		//populate the list in a new thread so that we dont block the UI thread
        start();
		
	}
	
	
	/**
	 * Populates the list after a currentDate, and currentTime have been set,
	 * this will display up to 6 next bus times for the current stop in a list
	 */
	private void populateList() {
		
		runOnUiThread(new Runnable() {   
			public void run(){  
				dateText.setText(dateLabel);
				timeText.setText(timeLabel);
			} 
		}); 

		SQLiteOperationsWrapper db = new SQLiteOperationsWrapper(this);
		db.open();
		
		int calendarDayCode = db.getCalendarDayCode(currentDay, Integer.parseInt(currentDate));
		
		// get the times for today starting at the current time or the time set
		// by the spinner
		timesList = db.getStopTimes(stopID, currentTime, calendarDayCode);
		
		// check if there are ANY stop times for this day (earlier than the requested time)
		boolean hasTimes = db.hasTimesOnDate(calendarDayCode, stopID);
		
		// if the result is null request the data from the server
		if (timesList == null && hasTimes == false) {

			String base = new BaseServicesURL().getStopURL();

			// request the data for this stop from the server
			// SET AT A DEFAULT TO REQUEST TIMES FOR A WEEKDAY FOR TESTING
			// PURPOSES
			String data = JSONBusStopHTTPGet.readBusStopJSONFeed(base + stopID
					+ "&t=" + currentDate + currentTime, this.getIntent());
			if (this.getIntent().getExtras().getBoolean("failedGetRequest")) {

				System.out.println("Failed to http get");
				runOnUiThread(new Runnable() {
					public void run() {
						Toast.makeText(
								ct,
								"There was an error, Please check your data connection",
								Toast.LENGTH_LONG).show();
					}
				});
				Intent intent2 = new Intent(this, MainMenuActivity.class);
				startActivity(intent2);
				finish();
				db.close();
				return;
			} else {
				timesList = StopParser.parse(data, stopID);
				
				if (timesList != null) {
					// insert the times data into the SQLite database
					for (int i = 0; i < timesList.size(); i++) {
						int tID = timesList.get(i).getTripID();
						int sID = timesList.get(i).getShapeID();
						String tH = timesList.get(i).getTripHeadsign();
						int dT = timesList.get(i).getDepartureTime();
						int rID = timesList.get(i).getRouteID();

						db.insertTripRow(tID, rID, tH, sID);
						db.insertStopTimeRow(stopID, tID, dT);
					}

					// get the next 6 times from the timesList returned from the parser
					timesList = getNextStopTimes();
				}
			}

		}
			
		db.close();

		// if the timesList is not null populate the list, if it is still null
		// then display message stating there are no more trips today
		if (timesList != null) {
			
			// if the timesList has fewer than 6 items set the arrays to the proper size
			// else set to 6
			if(timesList.size() < 6 ) {
				listSize = timesList.size();
			} else {
				listSize = 6;
			}
			
			// initialize arrays for displaying data in rows and for passing to
			// the viewRouteMapActivity
			shapeIDs = new int[listSize];
			times = new int[listSize];
			routeNames = new String[listSize];
			tripHeadSigns = new String[listSize];

			// populate the arrays from the timesList
			for (int i = 0; i < listSize; i++) {
				shapeIDs[i] = timesList.get(i).getShapeID();
				times[i] = timesList.get(i).getDepartureTime();
				routeNames[i] = "" + timesList.get(i).getRouteID();
				tripHeadSigns[i] = timesList.get(i).getTripHeadsign();
			}

			// set up the ListAdapter and the onItemClickListener
			final ListAdapter mAdapter = new MySimpleArrayAdapter(this, routeNames);
			
			runOnUiThread(new Runnable() {   
				public void run(){  
					lv.setAdapter(mAdapter);
				}
			}); 
			
			lv.setOnItemClickListener(new OnItemClickListener() {

				@Override
				public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
					
					// on click pass the shapeID and the tripID for use by
					// the ViewRouteMapActivity
					Intent intent = new Intent(getApplicationContext(),
							ViewRouteMapActivity.class);
					intent.putExtra(SHAPE_ID_KEY, shapeIDs[position]);
					intent.putExtra(TRIP_NAME_KEY, tripHeadSigns[position]);
					intent.putExtra(STOP_LAT_KEY, (int) (getIntent().getExtras().getInt(ViewStopsActivity.STOP_LAT_KEY)));
					intent.putExtra(STOP_LON_KEY, (int)(getIntent().getExtras().getInt(ViewStopsActivity.STOP_LONG_KEY)));
					startActivity(intent);
				}
			});
			
		} else {

			// display message when there are no more trips today
			String[] message = {"There are no more trips today"};
			
			final ListAdapter mAdapter = new ArrayAdapter<String>(this, R.layout.route_row, message);
			runOnUiThread(new Runnable() {   
				public void run(){  
					lv.setAdapter(mAdapter);
				}
			});
		}

	}
	
	
	/**
	 * Searches and returns the next 6 times from the timesList at the set time
	 * @return a list of at most 6 TripsTimesItems
	 */
	private List<TripsTimesItem> getNextStopTimes() {
		List<TripsTimesItem> nextTrips = new ArrayList<TripsTimesItem>();
		
		for (TripsTimesItem tti : timesList) {
			if (tti.getDepartureTime() >= Integer.parseInt(currentTime)) {
				nextTrips.add(tti);
				if (nextTrips.size() == 6) {
					break;
				}
			}
		}
		
		if (nextTrips.size() == 0) {
			nextTrips = null;
		}
		
		return nextTrips;
	}
		
	
	// time picker required method
	public void selectTimeOnClick(View v) {
		// setup the time picker dialog
		new TimePickerDialog(this, a, pHour, pMin, true).show();
	}
	
	
	// initialize the time picker listener
	TimePickerDialog.OnTimeSetListener a = new TimePickerDialog.OnTimeSetListener() {

		@Override
		public void onTimeSet(TimePicker view, int hourOfDay, int minute) {

			String tLabel = "";
			String ap = "";
			String tHour = "";
			String tMin = "";

			pHour = hourOfDay;
			pMin = minute;

			if (minute < 10) {
				tMin = "0" + minute;
				min = tMin;
			} else {
				tMin = "" + minute;
				min = tMin;
			}

			if (hourOfDay > 12) {
				tHour = "" + (hourOfDay - 12);
				ap = "pm";
			} else if (hourOfDay == 12) {
				tHour = "" + hourOfDay;
				ap = "pm";
			} else {
				tHour = "" + hourOfDay;
				ap = "am";
			}

			tLabel = tHour + ":" + tMin + ap;
			timeLabel = tLabel;

			if (hourOfDay < 10) {
				hour = "0" + hourOfDay;
			} else {
				hour = "" + hourOfDay;
			}


			// build the currentTime and add extra 0 if neccessary
			if (hourOfDay < 10) {
				currentTime = "0" + hourOfDay + min;
			} else {
				currentTime = "" + hour + min;
			}
			
			populateListInNewThread();
		}
	};
	
	
	// DatePicker dialog required method
	public void selectDateOnClick(View v) {
		
		// set up the date picker dialog
		new DatePickerDialog(this, t, date.get(Calendar.YEAR),
									  date.get(Calendar.MONTH),
									  date.get(Calendar.DAY_OF_MONTH)).show();
	}
	
	
	// get the date from the picker on selection and set currentDate, and currentDay
	// accordingly
	DatePickerDialog.OnDateSetListener t = new DatePickerDialog.OnDateSetListener() {
		
		@Override
		public void onDateSet(DatePicker view, int year, int monthOfYear,
				int dayOfMonth) {
			
			date.set(Calendar.YEAR, year);
			date.set(Calendar.MONTH, monthOfYear);
			date.set(Calendar.DAY_OF_MONTH, dayOfMonth);
			
			SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
			currentDate = df.format(date.getTime());
			
			df = new SimpleDateFormat("EEE, MMM d");
			dateLabel = df.format(date.getTime()); 
			
			currentDay = date.get(Calendar.DAY_OF_WEEK);
			
			populateListInNewThread();
		}
	};
	
	
	/**
	 * Saves the current stop to the favorites table or deletes it
	 * @param v the current view that holds the button
	 */
	public void saveFavoriteButtonOnClick(View v) {
		
		db = new SQLiteOperationsWrapper(this);
		db.open();
		
		// if the stop is already a favorite, delete it otherwise add it and
		// adjust button text accordingly
		if(db.isFavorite(stopID)) {
			db.deleteFavorite(stopID);
			saveFavoriteButton.setText(R.string.save_favorite_button_string);
			Toast.makeText(this, R.string.favorite_deleted, Toast.LENGTH_LONG).show();
		} else {
			db.insertFavoriteRow(stopID);
			saveFavoriteButton.setText(R.string.delete_favorite_button_string);
			Toast.makeText(this, R.string.favorite_saved, Toast.LENGTH_LONG).show();
		}
		
		db.close();
		
	}
	
	
	/**
	 * @author eric
	 * ArrayAdapter for the ListView.  This allows the displaying of the route
	 * number and the time of departure from this stop.  Pressing an item on
	 * the list will open the ViewRouteMapActivity for the specified route
	 */
	public class MySimpleArrayAdapter extends ArrayAdapter<String>  {

		Context context;
		
		public MySimpleArrayAdapter(Context context,String[] mStrings) {
			super(context, R.layout.stop_times_row,mStrings);

			this.context = context;
		}
		
		@Override
		public View getView(int position, View convertView, ViewGroup parent) {

			LayoutInflater inflater = (LayoutInflater) context
					.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			
			View rowView = inflater.inflate(R.layout.stop_times_row, parent, false);
			TextView tv = (TextView) rowView.findViewById(R.id.route_id);
			String tName = "" + routeNames[position];
			tv.setText(tName);
			TextView tv2 = (TextView) rowView.findViewById(R.id.arrival_time);
			
			// Format the time string to 5:00pm for easier view by user
			String time = "" + times[position];
			
			time = time.substring(0, time.length() - 2) + ":" + 
					time.substring(time.length() - 2, time.length());
			
			String[] splitTime = time.split(":");
			
			if(Integer.parseInt(splitTime[0]) > 12) {
				splitTime[0] = "" + (Integer.parseInt(splitTime[0]) - 12);
				time = splitTime[0] + ":" + splitTime[1] + "pm";
			} else if (Integer.parseInt(splitTime[0]) == 12){
				time = time + "pm";
			} else {
				time = time + "am";
			}
			
			tv2.setText(time);
			
			// highlight the next bus with red text
			if(position == 0) {
				tv.setTextColor(Color.RED);
				tv2.setTextColor(Color.RED);
			} else {
				tv.setTextColor(Color.BLACK);
				tv2.setTextColor(Color.BLACK);
			}
			
			return rowView;
		}
	}

	// draws the route on the map
	class PointOverlay extends ItemizedOverlay<OverlayItem> {
			
		   private ArrayList<OverlayItem> mapOverlays = new ArrayList<OverlayItem>();
			   
		   private Context context;
			   
		   public PointOverlay(Drawable defaultMarker) {
		        super(boundCenterBottom(defaultMarker));
		   }
			   
		   public PointOverlay(Drawable defaultMarker, Context context) {
		        this(defaultMarker);
		        this.context = context;
		   }

		   @Override
		   protected OverlayItem createItem(int i) {
		      return mapOverlays.get(i);
		   }

		   @Override
		   public int size() {
		      return mapOverlays.size();
		   }
			   
		   @Override
		   protected boolean onTap(int index) {
			   /*
		      OverlayItem item = mapOverlays.get(index);
		      AlertDialog.Builder dialog = new AlertDialog.Builder(context);
		      dialog.setTitle(item.getTitle());
		      dialog.setMessage(item.getSnippet());
		      dialog.show();
		      */
		      return true;
		   }
			   
		   public void addOverlay(OverlayItem overlay) {
			   mapOverlays.add(overlay);
		       this.populate();
		   }

	}

	@Override
	protected boolean isRouteDisplayed() {
		return false;
	}
	
	
	/**
	 * Populates the list in a new thread
	 */
	public void populateListInNewThread(){
			
		Runnable r = new Runnable() {
			public void run() {
				 populateList();
			}
		};
		
		Thread t = new Thread(r);
		t.start();

	}
	
	/**
	 * Starts a new thread for going through the cursor 
	 * and populating the list with items 
	 * This method is used to spawn a new hidden 
	 * thread witch calls the runWork method
	 */
	public void start() {
		Runnable r = new Runnable() {
			public void run() {
				runWork();
			}
		};
		
		Thread t = new Thread(r);
		t.start();
	}


	/**
	 * Work for the start method that is called in onCreate of the activity
	 */
	public void runWork() {
		// initialize widgets
			
		timesHeader = (TextView) findViewById(R.id.times_header);
		saveFavoriteButton = (Button) findViewById(R.id.saveFavoriteButton);
		lv = (ListView) findViewById(R.id.list);

			
		// sets rID to the value passed through the intent.
		stopID = getIntent().getIntExtra(ViewStopsActivity.STOP_ID_KEY, -1);
		stopName = getIntent().getStringExtra(ViewStopsActivity.STOP_NAME_KEY);
			
			
		// gets the current time to request start time of list
		d = new Date();
		currentTime = (String) DateFormat.format("kkmm", d.getTime());
		currentDate = (String) DateFormat.format("yyyyMMdd", d.getTime());
		currentDay = date.get(Calendar.DAY_OF_WEEK);
		dateLabel = (String) DateFormat.format("EEE, MMM d", d.getTime());
			
		// build time string for initial entry into spinner the time is rounded
		// down to the nearest 30 min increment in the format, "3:30am"
		min = (String) DateFormat.format("mm", d.getTime());
		hour = (String) DateFormat.format("hh", d.getTime());
		String ap = (String) DateFormat.format("aa", d.getTime());
		
		pHour = Integer.parseInt(currentTime.substring(0, 2));
		pMin = Integer.parseInt(currentTime.substring(2,4));
		
		// remove preceding 0 if present
		if(Integer.parseInt(hour) < 10) {
			hour = "" + hour.charAt(1);
		}
			
		// build the spinner time
		timeLabel = hour + ":" + min + ap;
			
		
		
		
		// open database to determine if this stop is a favorite to adjust label
		// on the saveFavoriteButton
		db = new SQLiteOperationsWrapper(this);
		db.open();
			
		if(db.isFavorite(stopID)) {
			runOnUiThread(new Runnable() {   
				public void run(){  
					saveFavoriteButton.setText(R.string.delete_favorite_button_string);
				} 
			}); 
		}
			
		db.close();
			
		runOnUiThread(new Runnable() {   
			public void run(){  
				// set the header to the name of the stop
				timesHeader.setText(stopName);
				progess.setVisibility(View.GONE);
				txtLoading.setVisibility(View.GONE); 
			} 
		});
		
		populateListInNewThread();
	}
	
	@Override
	public void onRestart(){
		super.onRestart();
		


	}
}	
